#include"process_cmp.h"
void pre_process_func(L_Func * L_fn)
{
	int count;
	count = get_compare_instruction(L_fn);
	if(count)
		annotate_compare_instruction(L_fn,count);
}

int get_compare_instruction(L_Func * L_fn)
{
    L_Cb * cb;
    L_Oper * op;
    int count = 0;
    for(cb = L_fn->first_cb; cb ;cb = cb->next_cb)
        for(op = cb->first_op; op ; op = op->next_op)
            if( op->proc_opc == Lop_RCMP || op->proc_opc == Lop_RCMP_F)
                count++;
    return count;
}

void annotate_compare_instruction(L_Func * L_fn,int count)
{
    L_Cb * cb;
    L_Oper * op;
    while(count > 0)
    {
        for(cb = L_fn->first_cb;cb;cb=cb->next_cb)
        {
            for(op = cb->first_op;op;op=op->next_op)
            {
                if(op->proc_opc == Lop_RCMP || op->proc_opc == Lop_RCMP_F)
                    break;
            }
            if(op)
                break;
        }
        if(cb)
        {
            L_Cb * cb1;
            L_Cb * cb2;
            L_Cb * cb3;
            L_Oper * movop;
            L_Oper * movop_next;
            L_Oper * newop;
            L_Operand *src0,*src1,*src3;
            L_Flow * flow;
            cb1 = L_new_cb(L_fn->n_cb + 1);
            cb2 = L_new_cb(L_fn->n_cb + 1);
            cb3 = L_new_cb(L_fn->n_cb + 1);
            L_insert_cb_after(L_fn,cb,cb1);
            L_insert_cb_after(L_fn,cb1,cb2);
            L_insert_cb_after(L_fn,cb2,cb3);
            movop = op->next_op;

            while(movop)
	         {
                movop_next = movop->next_op;
                //newop = L_create_new_op_using(movop->opc,movop);
                L_insert_oper_after(cb3,cb3->last_op,movop);
                movop = movop_next;
            }

            //update current cb
            newop = L_create_new_op( Lop_BR );
            newop->com[1] = op->com[1];
            newop->com[0] = op->com[0];
            newop->src[0] = L_copy_operand(op->src[0]);
            newop->src[1] = L_copy_operand(op->src[1]);
            //newop->proc_opc = LBWop_COMB_S;
            //newop->src[2] = L_new_label_operand(buf,L_OPERAND_LABEL);
            //newop->src[2] = L_new_gen_label_operand(buf);
            newop->src[2] = L_new_cb_operand(cb2);
            L_insert_oper_before(cb,op,newop);
            //update cb2
            newop = L_create_new_op(Lop_MOV);
            newop->dest[0] = L_copy_operand(op->dest[0]);
            newop->src[0] = L_new_int_operand(1,L_CTYPE_INT);
            //newop->proc_opc = LBWop_MOV_IMM32_S;
            L_insert_oper_after(cb2,cb2->last_op,newop);

            //update cb 1
            newop = L_create_new_op(Lop_MOV);
            newop->dest[0] = L_copy_operand(op->dest[0]);
            newop->src[0] = L_new_int_operand(0,L_CTYPE_INT);
            //newop->proc_opc = LBWop_MOV_IMM32_S;
            L_insert_oper_after(cb1,cb1->last_op,newop);

            newop = L_create_new_op(Lop_JUMP);
            //newop->proc_opc = LBWop_JUMP;
            newop->src[0] = L_new_cb_operand(cb3);
            L_insert_oper_after(cb1,cb1->last_op,newop);
            //delete all op after

            op->next_op = NULL;
            cb->last_op = op;
            L_delete_oper(cb,op);
            for(flow = cb->dest_flow;flow;flow=flow->next_flow)
            {
                L_Flow * cb3_flow =L_new_flow(flow->cc,cb3,flow->dst_cb,flow->weight);
                if(cb3->dest_flow == NULL)
                {
                    cb3->dest_flow = cb3_flow;
                }
                else
                    L_concat_flow(cb3->dest_flow,cb3_flow);
            }
            L_delete_all_flow(cb->dest_flow);
            cb->dest_flow = L_new_flow(0,cb,cb1,0);
            flow = L_new_flow(1,cb,cb2,0);
            L_concat_flow(cb->dest_flow,flow);
            cb1->dest_flow = L_new_flow(0,cb1,cb3,0);
            cb2->dest_flow = L_new_flow(0,cb2,cb3,0);

        }
        count--;
    }
}

